package com.xcity.game.combat.listener.combat;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Mine;
import com.xcity.db.entity.Player;
import com.xcity.game.combat.Combat;
import com.xcity.game.combat.Combat.Type;
import com.xcity.game.combat.CombatException;
import com.xcity.game.combat.CombatService;
import com.xcity.game.combat.CombatUtils;
import com.xcity.game.combat.Round;
import com.xcity.game.combat.builder.DefaultCombatBuilder;
import com.xcity.game.combat.listener.CombatListener;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.event.GameEvents;
import com.xcity.game.formation.Formation;
import com.xcity.game.map.MapService;
import com.xcity.game.map.MapUtils;
import com.xcity.game.npc.NpcTemplate;
import com.xcity.game.vip.VipUtils;
import com.xcity.pomelo.push.msg.CombatEndPush;
import com.xcity.pomelo.push.msg.StoneLackPush;
import com.xcity.pomelo.request.CombatInfoRequest;
import com.xcity.pomelo.request.CombatMineTakeRequest;
import com.xcity.pomelo.response.CombatInfoResponse;
import com.xcity.pomelo.response.CombatInfoResponse.TeamBuilder;
import com.xcity.pomelo.response.CombatResponse;

import naga.x.App;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Packet;
import naga.x.net.Session;

public class MineTakeCombatListener implements CombatListener {

	Player player;
	protected List<Employee> employees;
	protected Mine mine;
	
	protected int sourceFightValuel;
	protected static final Logger LOG = CombatService.LOG;
	
	static class Result{
		public int map;
		public int pos;
		public long ownerId;
		public String name;
		public String icon;
		public int type;
		public int leftSecond;
		public int mineId;
		public List<Long> guards;
		public int mapX;
		public int mapY;
		public Result(Player player, Mine mine){
			this.map = mine.getMap();
			int[] xy = MapUtils.map2mapXY(this.map);
			mapX = xy[0];//this.map % MapService.MAP_X_BLOCKS;
			mapY = xy[1];//this.map / MapService.MAP_X_BLOCKS;
			this.pos = mine.getPos();
			ownerId = player.getId();
			name = player.getName();
			icon = player.getIcon();
			type = mine.getMineType();
			leftSecond = (int) ((mine.getTakeTime() + (mine.getExtendCount()) * MapService.TAKE_MAX_DURATION - TimeUpdater.getInstance().now()) / 1000L);
			if(leftSecond < 0){
				leftSecond = 0;
			}
			mineId = mine.getId();
			guards = player.getMines().getEidList();
		}
	}

	@Deprecated //貌似用不上了
	@Override
	public void prepareCombat(Session session, CombatInfoRequest packet) throws CombatException {
		player = session.getClient();
		int map = packet.getMap();//TODO
		int pos = packet.getPos();//TODO
		init(map, pos, new long[]{0, 0, 0, 0});
		validate();
		sourceFightValuel = 0;
		TeamBuilder playerTeamBuilder = new TeamBuilder();//.setLeader(player)
		sourceFightValuel = sourceFightValuel + CombatUtils.calcCombatPower(player);
		for(int i = 0; i < employees.size(); i++){
			playerTeamBuilder.addMember(employees.get(i));
			if(employees.get(i) != null){
				sourceFightValuel = sourceFightValuel + CombatUtils.calcCombatPower(employees.get(i));
			}
		}
		
		TeamBuilder npcTeamBuilder = new TeamBuilder();
		NpcTemplate npcLeader = mine.getTypeTemp().getBoss();
		npcTeamBuilder.setLeader(npcLeader);
		NpcTemplate[] npcs = mine.getTypeTemp().getNpcs();
		for(int i = 0, len = npcs.length; i < len; i++){
			npcTeamBuilder.addMember(npcs[i]);
		}
		session.send(new CombatInfoResponse(packet.getSerial(), playerTeamBuilder.build(), npcTeamBuilder.build(), Formation.TYPE_MINE_DEFENSE));
	}

	@Override
	public CombatResponse create(CombatService service, Type type, Session session, Packet packet) throws CombatException {
		player = session.getClient();
		CombatMineTakeRequest req = (CombatMineTakeRequest)packet;
		int map = req.getMap();
		int pos = req.getPos();
		long[] eids = req.getEids();
		init(map, pos, eids);
		validate();
		mine.setState(MapService.MINE_STATE_FIGHTING);
		DefaultCombatBuilder builder = new DefaultCombatBuilder()
				.setType(Combat.Type.MINE_TAKE)
				.setListener(this)
//				.setSourceLeader(player)
				.addSourceMembers(employees);

//		sourceFightValuel = sourceFightValuel + CombatUtils.calcCombatPower(player);
		for(int i = 0; i < employees.size(); i++){
			if(employees.get(i) != null){
				sourceFightValuel = sourceFightValuel + CombatUtils.calcCombatPower(employees.get(i));
			}
		}
		NpcTemplate boss = mine.getTypeTemp().getBoss();
		builder.setDestLeader(boss != null? boss.toCombatabale() : null);
		NpcTemplate[] npcs = mine.getTypeTemp().getNpcs();
		for(int i = 0; i < npcs.length; i++){
			NpcTemplate npc = npcs[i];
			builder.addDestMember(npc != null? npc.toCombatabale() : null);
		}
		LOG.info("[MINETAKE]ID[{}]MAP[{}]POS[{}]", player.getId(), map, pos);
		return new CombatResponse(req.getSerial(), builder.build());
	}

	@Override
	public void end(Combat combat, boolean notify) {
		Result ref = null;
		long endTime = TimeUpdater.getInstance().now();
		CombatEndPush push = new CombatEndPush(Combat.FAIL, Combat.Type.MINE_TAKE, combat.getId());
		if(combat.getState() == Combat.State.SOURCE_WON){//combat.isWinner(player.getId())
			push.setResult(Combat.SUCC);
//			long[] eids = new long[]{0, 0, 0, 0};
//			for(int i = 0; i < employees.size(); i++){
//				if(employees.get(i) != null){
//					eids[i] = employees.get(i).getId();
//				}
//			}
			List<Long> eids = new ArrayList<Long>();
			for(int i = 0; i < employees.size(); i++){
				if(employees.get(i) != null){
					eids.add(employees.get(i).getId());
				}else{
					eids.add(0L);
				}
			}
			App.getApp().getServiceManager().get(MapService.class).handleMineBattleEnd(mine, player, null, endTime, true, eids, sourceFightValuel);
			ref = new Result(player, mine);
			push.setRef(ref);
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_MINE_TAKEN, player, mine);
		}else{
			App.getApp().getServiceManager().get(MapService.class).handleMineBattleEnd(mine, player, null, 0, false, null, 0);
		}
		mine.setState(MapService.MINE_STATE_NONE);
		if (notify) {
			player.send(push);
		}
		LOG.info("[MINETAKE]ID[{}]MAP[{}]POS[{}]RESULT[{}]", player.getId(), mine.getMap(), mine.getPos(), push.getResult());
	}
	
	public void init(int map, int pos, long[] eids) throws CombatException{
		mine = App.getApp().getServiceManager().get(MapService.class).findMineByMapPos(map, pos);
		if(mine == null){
			throw new CombatException(MessageConst.MINE_NOT_EXIST);
		}
		if(eids == null || eids.length != 4){
			throw new CombatException(MessageConst.MINE_WRONG_EMPLOYEE);
		}
//		employees = Arrays.asList(player.getFormations().get(Formation.TYPE_MINE_DEFENSE).getUnits());
		employees = new ArrayList<Employee>();
		int emptyCount = 0;
		for(long eid : eids){
			Employee e = eid != 0L ? player.getEmployees().get(eid) : null;
			employees.add(e);
			if(e == null){
				emptyCount++;
			}
		}
		if(emptyCount >= 4){
			throw new CombatException(MessageConst.MINE_MUST_HAVE_EMPLOYEE);
		}
	}
	
	public void validate() throws CombatException{
		if(mine.getOwnerId() != 0){
			throw new CombatException(MessageConst.MINE_TAKEN);
		}
		if(player.getLevel() < MapService.SHOW_MAP_LEVEL){
			throw new CombatException(MessageFormat.format(MessageConst.MINE_LEVEL_LIMIT, MapService.SHOW_MAP_LEVEL) );
		}
		if(player.getMines().mineTakenCount() >= VipUtils.getTemplate(player.getVipLvl()).getMineTakeLimit()){
			throw new CombatException(MessageConst.MINE_TAKE_LIMIT);
		}
		if(mine.getTypeTemp().getCostStone() > 0 && player.getStone() < mine.getTypeTemp().getCostStone()){
			player.send(StoneLackPush.DEFAULT);
			throw new CombatException(MessageConst.MINE_NO_STONE);
		}
		if(mine.getTypeTemp().getCostStr() > 0 && player.getStrength() < mine.getTypeTemp().getCostStr()){
			throw new CombatException(MessageConst.MINE_NO_STR);
		}
		if(mine.getState() != MapService.MINE_STATE_NONE){
			throw new CombatException(MessageConst.MINE_FIGHTING);
		}
		if(mine.getTypeTemp().getCostStone() > 0 && !player.costStone(mine.getTypeTemp().getCostStone(), Cause.MINE_TAKE)){
			throw new CombatException(MessageConst.MINE_NO_STONE);
		}
		if(mine.getTypeTemp().getCostStr() > 0 && !player.decStrength(mine.getTypeTemp().getCostStr(), Cause.MINE_TAKE)){
			throw new CombatException(MessageConst.MINE_NO_STR);
		}
	}
	
	@Override
	public void roundStart(Round round) {
	}

	@Override
	public void roundEnd(Round round) {
	}

}
